#include "PackageParser.h"

#include "PinOneOrientationParser.h"
#include "PackageTypeParser.h"
#include "QStringParser.h"
#include "AssemblyDrawingParser.h"
#include "PinParser.h"
#include "OutlineParser.h"
#include "SilkScreenParser.h"
#include "DoubleParser.h"
#include "LandPatternParser.h"
#include "LocationParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

PackageParser::PackageParser(
    QStringParser *&_nameParser
    , PackageTypeParser *&_typeParser
    , QStringParser *&_pinOneParser
    , PinOneOrientationParser *&_pinOneOrientationParser
    , DoubleParser *&_heightParser
    , QStringParser *&_commentParser
    , OutlineParser *&_outlineParser
    , LocationParser *&_pickupPointParser
    , LandPatternParser *&_landPatternParser
    , SilkScreenParser *&_silkScreenParser
    , AssemblyDrawingParser *&_assemblyDrawingParser
    , PinParser *&_pinParser
):    m_nameParser(_nameParser)
    , m_typeParser(_typeParser)
    , m_pinOneParser(_pinOneParser)
    , m_pinOneOrientationParser(_pinOneOrientationParser)
    , m_heightParser(_heightParser)
    , m_commentParser(_commentParser)
    , m_outlineParser(_outlineParser)
    , m_pickupPointParser(_pickupPointParser)
    , m_landPatternParser(_landPatternParser)
    , m_silkScreenParser(_silkScreenParser)
    , m_assemblyDrawingParser(_assemblyDrawingParser)
    , m_pinParser(_pinParser)
{

}

bool PackageParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new Package());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("name")))
    {
        data = reader->attributes().value(QStringLiteral("name"));
        if (!m_nameParser->parse(reader, data))
            return false;
        m_result->name = m_nameParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("name: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("type")))
    {
        data = reader->attributes().value(QStringLiteral("type"));
        if (!m_typeParser->parse(reader, data))
            return false;
        m_result->type = m_typeParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("type: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("pinOne")))
    {
        data = reader->attributes().value(QStringLiteral("pinOne"));
        if (!m_pinOneParser->parse(reader, data))
            return false;
        m_result->pinOneOptional = Optional<QString>(m_pinOneParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("pinOneOrientation")))
    {
        data = reader->attributes().value(QStringLiteral("pinOneOrientation"));
        if (!m_pinOneOrientationParser->parse(reader, data))
            return false;
        m_result->pinOneOrientationOptional = Optional<PinOneOrientation>(m_pinOneOrientationParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("height")))
    {
        data = reader->attributes().value(QStringLiteral("height"));
        if (!m_heightParser->parse(reader, data))
            return false;
        m_result->heightOptional = Optional<Double>(m_heightParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("comment")))
    {
        data = reader->attributes().value(QStringLiteral("comment"));
        if (!m_commentParser->parse(reader, data))
            return false;
        m_result->commentOptional = Optional<QString>(m_commentParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
        if (name == QStringLiteral("Outline"))
        {
            if (!m_outlineParser->parse(reader))
                return false;
            auto result = m_outlineParser->result();
            m_result->outline = result;
        }
        else if (name == QStringLiteral("PickupPoint"))
        {
            if (!m_pickupPointParser->parse(reader))
                return false;
            auto result = m_pickupPointParser->result();
            m_result->pickupPointOptional = Optional<Location*>(result);
        }
        else if (name == QStringLiteral("LandPattern"))
        {
            if (!m_landPatternParser->parse(reader))
                return false;
            auto result = m_landPatternParser->result();
            m_result->landPatternOptional = Optional<LandPattern*>(result);
        }
        else if (name == QStringLiteral("SilkScreen"))
        {
            if (!m_silkScreenParser->parse(reader))
                return false;
            auto result = m_silkScreenParser->result();
            m_result->silkScreenOptional = Optional<SilkScreen*>(result);
        }
        else if (name == QStringLiteral("AssemblyDrawing"))
        {
            if (!m_assemblyDrawingParser->parse(reader))
                return false;
            auto result = m_assemblyDrawingParser->result();
            m_result->assemblyDrawingOptional = Optional<AssemblyDrawing*>(result);
        }
        else if (name == QStringLiteral("Pin"))
        {
            if (!m_pinParser->parse(reader))
                return false;
            auto result = m_pinParser->result();
            m_result->pinList.append(result);
        }
        else
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

Package *PackageParser::result()
{
    return m_result.take();
}

}